<template>
  <dialog ref="dialogRef" class="attr-viewer wide">
    <form method="dialog" class="dialog-body" @submit.prevent="close">
      <div class="dialog-header">
        <h3>
          <svg class="title-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <rect x="3" y="4" width="18" height="16" rx="2" ry="2" />
            <path d="M7 4v16M17 4v16" />
          </svg>
          属性
        </h3>
        <button type="button" class="close-x" @click="close" aria-label="关闭">
          <svg class="close-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <line x1="18" y1="6" x2="6" y2="18" />
            <line x1="6" y1="6" x2="18" y2="18" />
          </svg>
        </button>
      </div>
      <div class="section attr-matrix grouped" v-if="entry">
        <template v-if="allDefs.length">
          <div v-if="sizeDefs.length" class="group-block size-group">
            <header class="group-title"><span class="dot size"></span><h4>尺寸</h4></header>
            <div class="matrix size-matrix">
              <div v-for="(def,idx) in sizeDefs" :key="def.code" class="attr-tile" :class="[{ empty: !displayValue(def.code) }, gradientClass(idx)]" :style="tileDelay(idx)" role="group" :aria-label="def.name">
                <div class="tile-strip" aria-hidden="true"></div>
                <div class="tile-head">
                  <span class="name" :title="def.name">{{ def.name }}<span v-if="def.required" class="star" aria-hidden="true">*</span></span>
                </div>
                <div class="tile-value multi" :class="{ placeholder: !displayValue(def.code) }" :title="displayValue(def.code) || '空'">
                  <span class="val-text" :class="{ multiline: isLong(def) }">{{ displayValue(def.code) || '—' }}</span>
                  <span v-if="def.unit && def.control==='NumericTextBox' && displayValue(def.code)" class="unit-badge">{{ def.unit }}</span>
                </div>
              </div>
            </div>
          </div>
          <div v-if="basicDefs.length" class="group-block basic-group">
            <header class="group-title"><span class="dot basic"></span><h4>基本信息</h4></header>
            <div class="matrix basic-matrix">
              <div v-for="(def,idx) in basicDefs" :key="def.code" class="attr-tile" :class="[{ empty: !displayValue(def.code) }, gradientClass(idx+sizeDefs.length)]" :style="tileDelay(idx+sizeDefs.length)" role="group" :aria-label="def.name">
                <div class="tile-strip" aria-hidden="true"></div>
                <div class="tile-head">
                  <span class="name" :title="def.name">{{ def.name }}<span v-if="def.required" class="star" aria-hidden="true">*</span></span>
                </div>
                <div class="tile-value multi" :class="{ placeholder: !displayValue(def.code) }" :title="displayValue(def.code) || '空'">
                  <span class="val-text" :class="{ multiline: isLong(def) }">{{ displayValue(def.code) || '—' }}</span>
                  <span v-if="def.unit && def.control==='NumericTextBox' && displayValue(def.code)" class="unit-badge">{{ def.unit }}</span>
                </div>
              </div>
            </div>
          </div>
          <div v-if="remarkDefs.length" class="group-block remark-group">
            <header class="group-title"><span class="dot remark"></span><h4>备注</h4></header>
            <div class="remark-list">
              <div v-for="(def,idx) in remarkDefs" :key="def.code" class="attr-tile long" :class="[{ empty: !displayValue(def.code) }, gradientClass(idx+sizeDefs.length+basicDefs.length)]" :style="tileDelay(idx+sizeDefs.length+basicDefs.length)" role="group" :aria-label="def.name">
                <div class="tile-strip" aria-hidden="true"></div>
                <div class="tile-head">
                  <span class="name" :title="def.name">{{ def.name }}<span v-if="def.required" class="star" aria-hidden="true">*</span></span>
                </div>
                <div class="tile-value multi" :class="{ placeholder: !displayValue(def.code) }" :title="displayValue(def.code) || '空'">
                  <span class="val-text multiline">{{ displayValue(def.code) || '—' }}</span>
                </div>
              </div>
            </div>
          </div>
        </template>
        <div v-else class="no-attr-tip base">该条目暂无属性。</div>
      </div>
      <div class="dialog-actions footer">
        <button type="button" class="btn primary" @click="close">
          <svg class="btn-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
            <polyline points="20,6 9,17 4,12" />
          </svg>
          关闭
        </button>
      </div>
    </form>
  </dialog>
</template>

<script setup lang="ts">
import { ref, reactive, computed } from 'vue';
import type { MaterialAttributeDefinition, AttributeOptionItem } from '../mock/materialAttributes';

interface AttributeEntry {
  id: string;
  attributeSpec?: string;
  attributeDefinitions?: MaterialAttributeDefinition[];
  attributeValues?: Record<string, any>;
  categoryCode?: string; // 新增：便于重新获取下拉选项 label
}

const dialogRef = ref<HTMLDialogElement | null>(null);
const entry = ref<AttributeEntry | null>(null);
const optionCache = reactive<Record<string, AttributeOptionItem[]>>({}); // key: def.code
const loading = reactive<Record<string, boolean>>({});
// 已移除搜索/复制/密度功能，保持最小展示逻辑

async function ensureOptions(def: MaterialAttributeDefinition) {
  if (def.control !== 'DropDownList') return;
  if (!entry.value?.categoryCode) return;
  if (optionCache[def.code]?.length || loading[def.code]) return;
  loading[def.code] = true;
  try {
    // 优先使用定义上已有的 selectItems（若由后端返回并映射到 def.selectItems）
    if ((def as any).selectItems && Array.isArray((def as any).selectItems) && (def as any).selectItems.length) {
      optionCache[def.code] = (def as any).selectItems.map((s: any) => ({ value: String(s.value ?? s.id ?? s.value), label: s.label ?? s.itemName }));
    } else {
      // 后端未提供下拉选项且无 selectItems，保持空数组；不再使用假数据回退。
      optionCache[def.code] = [];
    }
  } finally { loading[def.code] = false; }
}

async function preloadDropdownLabels(defs?: MaterialAttributeDefinition[]) {
  if (!defs) return;
  const tasks = defs.filter(d => d.control === 'DropDownList').map(d => ensureOptions(d));
  if (tasks.length) await Promise.allSettled(tasks);
}

async function open(e: AttributeEntry) {
  entry.value = e;
  // 预加载下拉标签
  await preloadDropdownLabels(e.attributeDefinitions);
  const el = dialogRef.value; if (el) { el.classList.remove('closing'); el.showModal(); }
}

function displayValue(code: string) {
  const defs = entry.value?.attributeDefinitions || [];
  const def = defs.find(d => d.code === code);
  const values = entry.value?.attributeValues; if (!values || !def) return '';
  let v = values[code];
  if (v == null || v === '') return '';
  if (def.control === 'DropDownList') {
    const opts = optionCache[def.code] || [];
    const label = opts.find(o => o.value === v)?.label;
    return label || String(v);
  }
  // 数值控件的单位单独用 unit-badge 展示，避免重复
  if (def.control === 'NumericTextBox') {
    return String(v);
  }
  return String(v);
}

function close() {
  const el = dialogRef.value; if (!el) return; if (el.classList.contains('closing')) return; el.classList.add('closing');
  const done = () => { el.removeEventListener('transitionend', done); el.classList.remove('closing'); el.close(); };
  el.addEventListener('transitionend', done); setTimeout(done, 380);
}

function gradientClass(idx: number) {
  const palette = ['g1','g2','g3','g4','g5','g6'];
  return palette[idx % palette.length];
}
function tileDelay(idx: number) { return { '--delay': (idx * 35)+'ms' }; }

// 扁平化：按照原 definitions 顺序（若有 sort 字段则先按 sort 排）展示
const allDefs = computed(() => (entry.value?.attributeDefinitions || []).slice());
//const sizeDefs = computed(() => allDefs.value.filter(d => (d as any).group === 'size' || /^(length|width|height|thickness)$/i.test(d.code)));
const sizeDefs = computed(() =>
allDefs.value.filter(d => {
const inSizeGroup = (d as any).group === 'size';
const codeMatch = /^(length|width|height|thickness)$/i.test(String((d as any).code || ''));
const nameStr = String((d as any).name || (d as any).propertyName || '');
const nameMatch = /(长|宽|高|厚|长度|宽度|高度|厚度)/.test(nameStr);
return inSizeGroup || codeMatch || nameMatch;
})
);

const remarkDefs = computed(() => allDefs.value.filter(d => (d as any).group === 'remark' || /remark|memo|note|desc|说明|备注/i.test(d.code)));
const basicDefs = computed(() => allDefs.value.filter(d => !sizeDefs.value.includes(d) && !remarkDefs.value.includes(d)));
function isLong(def: MaterialAttributeDefinition) { return /remark|memo|note|desc|说明|备注/i.test(def.code + def.name); }

defineExpose({ open, close });
</script>

<style scoped>
.attr-viewer::backdrop { background: rgba(15,23,42,.5); backdrop-filter: blur(6px); animation: backdropFadeIn .32s ease; }
@keyframes backdropFadeIn { from {opacity:0;} to {opacity:1;} }
.attr-viewer { border:1px solid #e2e8f0; border-radius:20px; padding:0; width:460px; max-width:92vw; box-shadow:0 18px 42px -12px rgba(15,23,42,.3),0 6px 18px -6px rgba(15,23,42,.18); overflow:hidden; animation: dialogFadeSlide .34s cubic-bezier(.4,0,.2,1); background:#fff; transition: opacity .3s cubic-bezier(.4,0,.2,1), transform .34s cubic-bezier(.4,0,.2,1); }
.attr-viewer.wide { width:1080px; max-width:95vw; }
.attr-viewer.closing { opacity:0; transform:translateY(-12px); pointer-events:none; }
.attr-viewer.closing::backdrop { animation: backdropFadeOutAttr .32s ease forwards; }
@keyframes backdropFadeOutAttr { to { background:rgba(15,23,42,0); backdrop-filter:blur(0); } }
@keyframes dialogFadeSlide { from {opacity:0; transform:translateY(14px);} to {opacity:1; transform:translateY(0);} }
.dialog-body { display:flex; flex-direction:column; gap:1.1rem; padding:1.35rem 1.5rem 1.5rem; background:linear-gradient(145deg,#ffffff,#f8fafc 70%); }
.dialog-header { position:relative; display:flex; align-items:center; gap:.55rem; min-height:46px; padding:.25rem 0; }
.dialog-header h3 { margin:0; font-size:16px; font-weight:600; display:flex; align-items:center; gap:.5rem; padding-right:2.5rem; }
.title-icon { width:18px; height:18px; stroke:#0ea5e9; stroke-width:1.8; }
.close-x { position:absolute; top:4px; right:4px; width:34px; height:34px; padding:0; background:transparent; border:none; cursor:pointer; border-radius:10px; color:#6b7280; transition:all .2s; display:flex; align-items:center; justify-content:center; }
.close-x:hover { background:linear-gradient(135deg,#fee2e2,#fecaca); color:#dc2626; transform:rotate(90deg); }
.close-x:active { transform:rotate(90deg) scale(.9); }
.close-icon { width:18px; height:18px; }

.section.attr-matrix { padding:.4rem 0 .4rem; }
.matrix { display:grid; grid-template-columns:repeat(auto-fill,minmax(200px,1fr)); gap:1rem 1.1rem; align-items:stretch; }
.attr-matrix.grouped { display:flex; flex-direction:column; gap:1.6rem; }
.group-block { display:flex; flex-direction:column; gap:.9rem; }
.group-title { display:flex; align-items:center; gap:.55rem; padding-left:.2rem; }
.group-title h4 { margin:0; font-size:13px; font-weight:700; letter-spacing:.05em; text-transform:uppercase; color:#475569; }
.dot { width:10px; height:10px; border-radius:50%; background:#64748b; box-shadow:0 0 0 4px rgba(100,116,139,.15); }
.dot.size { background:#2563eb; box-shadow:0 0 0 4px rgba(37,99,235,.15); }
.dot.basic { background:#0d9488; box-shadow:0 0 0 4px rgba(13,148,136,.18); }
.dot.remark { background:#9333ea; box-shadow:0 0 0 4px rgba(147,51,234,.18); }
.size-matrix { grid-template-columns:repeat(auto-fit,minmax(140px,1fr)); }
.remark-list { display:flex; flex-direction:column; gap:1rem; }
.attr-tile.long { width:100%; }
.val-text.multiline { white-space:pre-wrap; word-break:break-word; }
@media (min-width:1220px) { .matrix { grid-template-columns:repeat(auto-fill,minmax(210px,1fr)); } }
@media (max-width:760px) { .matrix { grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); } }
.attr-tile { position:relative; display:flex; flex-direction:column; gap:.55rem; padding:1rem .95rem 1.05rem; border:1px solid #e2e8f0; background:linear-gradient(145deg,#ffffff,#f8fafc 70%); border-radius:18px; box-shadow:0 6px 18px -6px rgba(15,23,42,.18),0 2px 6px -2px rgba(15,23,42,.08); overflow:hidden; cursor:default; animation: tileIn .55s cubic-bezier(.16,1,.3,1) var(--delay,0ms) both; transition:box-shadow .4s cubic-bezier(.4,0,.2,1), transform .45s cubic-bezier(.4,0,.2,1); }
.attr-tile:before { content:""; position:absolute; inset:0; background:radial-gradient(circle at 30% 25%,rgba(255,255,255,.55),transparent 70%); opacity:.55; pointer-events:none; mix-blend-mode:overlay; }
.attr-tile:hover { transform:translateY(-6px); box-shadow:0 14px 34px -10px rgba(15,23,42,.3),0 6px 18px -6px rgba(15,23,42,.22); }
.attr-tile:hover { transform:translateY(-6px); box-shadow:0 14px 36px -10px rgba(59,130,246,.45),0 6px 18px -6px rgba(59,130,246,.3); }
.attr-tile.empty { opacity:.55; }
.attr-tile.dense { padding:.55rem .6rem .6rem; border-radius:14px; }
.tile-strip { position:absolute; top:0; left:0; right:0; height:5px; background:linear-gradient(90deg,#3b82f6,#8b5cf6,#06b6d4); opacity:.85; }
.tile-head { display:flex; align-items:center; gap:.4rem; font-size:12px; font-weight:600; letter-spacing:.02em; color:#334155; padding-top:.15rem; }
.tile-head .star { color:#dc2626; font-size:12px; font-weight:700; }
.tile-value { font-size:14px; font-weight:600; color:#0f172a; line-height:1.35; word-break:break-word; font-variant-numeric:tabular-nums; }
.tile-value.multi { display:flex; flex-wrap:wrap; align-items:center; gap:.4rem .5rem; }
.tile-value.placeholder { color:#94a3b8; font-weight:500; font-style:italic; }
.unit-badge { font-size:11px; font-weight:600; background:linear-gradient(135deg,#eff6ff,#ffffff); border:1px solid #93c5fd; color:#1e3a8a; padding:.15rem .4rem; border-radius:6px; letter-spacing:.04em; }
.attr-tile.g1 .tile-strip { background:linear-gradient(90deg,#2563eb,#3b82f6); }
.attr-tile.g2 .tile-strip { background:linear-gradient(90deg,#0d9488,#14b8a6); }
.attr-tile.g3 .tile-strip { background:linear-gradient(90deg,#059669,#10b981); }
.attr-tile.g4 .tile-strip { background:linear-gradient(90deg,#d97706,#f59e0b); }
.attr-tile.g5 .tile-strip { background:linear-gradient(90deg,#9333ea,#a855f7); }
.attr-tile.g6 .tile-strip { background:linear-gradient(90deg,#6b7280,#94a3b8); }
/* subtle background hue per tile */
.attr-tile.g1 { background:linear-gradient(145deg,#f0f7ff,#ffffff 70%); }
.attr-tile.g2 { background:linear-gradient(145deg,#ecfdfd,#ffffff 70%); }
.attr-tile.g3 { background:linear-gradient(145deg,#ecfdf5,#ffffff 70%); }
.attr-tile.g4 { background:linear-gradient(145deg,#fefce8,#ffffff 70%); }
.attr-tile.g5 { background:linear-gradient(145deg,#faf5ff,#ffffff 70%); }
.attr-tile.g6 { background:linear-gradient(145deg,#f1f5f9,#ffffff 70%); }

@keyframes tileIn { from { opacity:0; transform:translateY(18px) scale(.96);} to { opacity:1; transform:translateY(0) scale(1);} }
.fade-scale-enter-active,.fade-scale-leave-active { transition:all .35s cubic-bezier(.4,0,.2,1); }
.fade-scale-enter-from { opacity:0; transform:scale(.9); }
.fade-scale-leave-to { opacity:0; transform:scale(.9); }
.no-attr-tip { font-size:13px; color:#64748b; font-weight:500; text-align:center; padding:1.1rem 0; background:#f1f5f9; border:1px dashed #cbd5e1; border-radius:14px; }
.no-attr-tip.subtle { background:transparent; border-style:dotted; }
.no-attr-tip.base { margin-top:.6rem; }
.dialog-actions.footer { margin-top:.5rem; display:flex; justify-content:flex-end; padding-top:1rem; border-top:1px solid #e2e8f0; }
.btn { cursor:pointer; border:1px solid transparent; padding:.75rem 1.5rem; border-radius:12px; font-size:14px; font-weight:600; letter-spacing:.025em; box-shadow:0 2px 4px rgba(0,0,0,.1); transition:all .3s cubic-bezier(.4,0,.2,1); display:inline-flex; align-items:center; gap:.5rem; }
.btn-icon { width:16px; height:16px; }
.btn.primary { background:#0ea5e9; border-color:#0ea5e9; color:#fff; }
.btn.primary:hover { background:#0284c7; }
</style>
